local print = print
local tconcat = table.concat
local tinsert = table.insert
local srep = string.rep
local type = type
local pairs = pairs
local tostring = tostring
local next = next

local socket = require "client.websocket"
local protobuf = require "protobuf"
local parser = require "parser"

local md5 = require "md5"

parser.register("./app/proto/primary.proto")
parser.register("./app/bjlnode/bjl.proto")
parser.register("./app/lhdnode/lhd.proto")
parser.register("./app/rbnode/rb.proto")
parser.register("./app/ttznode/ttz.proto")
parser.register("./app/brnnnode/brnn.proto")
parser.register("./app/bmnode/bm.proto")
parser.register("./app/dicenode/dice.proto")

local platform2login_key = "p2l_salt"
local decode = require "protopack"

math.randomseed(os.time())
math.random()

local gamename = "lhd"
local gatefd_to_rid = {}
local login_fds = { }
local gate_fds = { }
local game_fds = { }
local ready_fds = { }

local NetTool = {}

-----

--是否显示打印
local is_print = false

------------------------
--辅助函数

--打印table
local function print_t(root)
	local cache = {  [root] = "." }
	local function _dump(t,space,name)
		local temp = {}
		for k,v in pairs(t) do
			local key = tostring(k)
			if cache[v] then
				tinsert(temp,"+" .. key .. " {" .. cache[v].."}")
			elseif type(v) == "table" then
				local new_key = name .. "." .. key
				cache[v] = new_key
				tinsert(temp,"+" .. key .. _dump(v,space .. (next(t,k) and "|" or " " ).. srep(" ",#key),new_key))
			else
				tinsert(temp,"+" .. key .. " [" .. tostring(v).."]")
			end
		end
		return tconcat(temp,"\n"..space)
	end
	print(_dump(root, "",""))
end

--打印
local Print = function (...)
    if is_print then
        local args = table.pack(...)
        for k,arg in pairs(args) do
            if type(arg) == "table" then
                print_t(arg)
            elseif k ~= "n" then
                print(arg)
            end
        end
    end
end

--
--计算总权值
--
local function calculate_total_weight(w_list)
    local total_weight = 0
    for id,w in pairs(w_list) do
        total_weight = total_weight + w
    end

    return total_weight
end

--根据权值表，获取随机结果
local function get_random_result_by_weightlist(weight_list, total_w)
    total_w = total_w or calculate_total_weight(weight_list)
    local r = math.random(1,total_w)
    local sum = 0
    for id,w in pairs(weight_list) do
        sum = sum + w
        if r <= sum then
            return id
        end
    end
    return   
end

--延时ns
local function sleep(ts)
    local dest_tm = os.time() + ts
    while dest_tm > os.time() do
        socket.usleep(100)
        coroutine.yield()
    end
end

--等待响应
local function wait_response(fd)
    while true do
        if NetTool.dispatch_package(fd) == 1 then
            break
        else
            coroutine.yield()
        end
    end
end

--------------------
--随机下注

--下注列表
local game_bet_list = {
    sgj  = {108,107,106,105,104,103,102,101},
    bm   = {2101,2102,2103,2104,1101,1102,1103,1104},
    fqzs = {101,111,102,105,106,107,108,104,109,110,103},
    bjl  = {1101,1102},
    lhd  = {1101,1102},
    rb  = {1101,1102},
    ttz  = {1101,1102,1103},
    brnn = {1101,1102,1103,1104},
    dice = {1101,1102,1103,2101,2102,2103,2104,2105,2106,2107,2108,2109,2110},
}

--底注列表
local game_score_list = {
    fqzs = {100, 500, 1000, 5000,10000, 50000, 100000},
    bm   = {100, 500, 1000, 5000,10000, 50000, 100000},
    sgj  = {100, 500, 1000, 5000,10000, 50000, 100000},
    lhj  = {1, 5, 10, 50, 100, 500},
    bjl  = {100, 500, 1000, 5000,10000, 50000, 100000},
    lhd  = {100, 500, 1000, 5000,10000, 50000, 100000},
    rb  = {100, 500, 1000, 5000,10000, 50000, 100000},
    ttz = {100, 500, 1000, 5000,10000, 50000, 100000},
    brnn = {100, 500, 1000, 5000,10000, 50000, 100000},
    dice = {100, 500, 1000, 5000,10000, 50000, 100000},
}

--筹码权值表
local score_weights = {
    [1] = 200,
    [2] = 100,
    [3] = 10,
    [4] = 5,
    [5] = 0,
    [6] = 0,
    [7] = 0,
}

--线数权值表
local line_weights = {
    [1] = 50,
    [2] = 50,
    [3] = 100,
    [4] = 100,
    [5] = 100,
    [6] = 200,
    [7] = 200,
    [8] = 200,
    [9] = 200,
}

--机器人下注
local function random_bet(fd, bet_time)
    --处理下注
    local function handle_bet(fd, bs_list, score_index, id, bet_cnt)
        local requestmsg = {
            action_type = 2,
            base_score_index = score_index,
        }
        NetTool.send_request(fd, gamename .. ".doaction", requestmsg)
        wait_response(fd)

        local st = os.time()
        local cur_score = bs_list[score_index]
        for i = 1,bet_cnt do
            local msg = {
                bet_item_id = id,
                bet_score = cur_score,
                action_type = 1,
            }
            NetTool.send_request(fd, gamename .. ".doaction", msg)
            wait_response(fd)
        end
        local ed = os.time()

        return (ed - st)
    end
    
    --下注
    local function do_bet(fd, betbtn_list, bs_list, bet_time)
        local total_tm = 0
        local total_w = calculate_total_weight(score_weights)

        while bet_time - total_tm > 0 do
            --随机下3~5注
            local bet_cnt = math.random(3,5)

            --随机底注
            local score_index = get_random_result_by_weightlist(score_weights,total_w)

            --随机下注项
            local idx = math.random(1,#betbtn_list)
            local id = betbtn_list[idx]

            --下注
            total_tm = total_tm + handle_bet(fd, bs_list, score_index, id, bet_cnt)

            --随机延时0.5~1s
            local dy = math.random(5,10) / 10
            total_tm = total_tm + dy
            sleep(dy)
        end
    end

    do_bet(fd,game_bet_list[gamename],game_score_list[gamename],bet_time)
end

------------------------------

------------
--自动开始
local function auto_start(fd)
    if gamename ~= "lhj" and gamename ~= "fish" then
        return
    end

    --选择一个底注
    local score_index = get_random_result_by_weightlist(score_weights) 

    --切换底注
    local requestmsg = {
        action_type = 2,
        base_score_index = score_index,
    }
    NetTool.send_request(fd, gamename .. ".doaction", requestmsg)
    wait_response(fd)

    --切换线数,老虎机才需要
    if gamename == "lhj" then
         --选择一个线数
        local line = get_random_result_by_weightlist(line_weights) 
        local at = 4
        if line == 9 then
            at = 5
        end
        for i = 2,line do
            NetTool.send_request(fd, gamename .. ".doaction", {action_type = at})
            wait_response(fd)
            if line == 9 then
                break
            end
        end
    end
    
    --设置自动开始
    NetTool.send_request(fd, gamename .. ".doaction", {action_type = 6})
    wait_response(fd)

    --开始游戏
    NetTool.send_request(fd, gamename .. ".doaction", {action_type = 1})
end

------------------------

--生成token
local function gentoken(username)
    local tokentime = os.time()
    local newtoken = md5.sumhexa(username .. tokentime .. platform2login_key ) .. tokentime
    return newtoken
end

--发送包
local function send_package(fd, pack)
	-- 使用了websocket ，会自己组织帧格式的
	socket.send(fd, pack)
end

--接收包
local function recv_package(fd)
	local r, istimeout = socket.recv(fd, 100)
	if not r then
		return nil
	end
	if r == ""  and (not istimeout ) then
		return -1
	end
	return r
end

--打印请求
local function print_request(name, args)
    if name == gamename .. ".nodeheart" then
        return
    end

    Print('------ begin request --------')
	Print(name,args)
    Print('------ end request ----------')
end

--打印回应
local function print_response(msghead, msgbody)
    if msghead.msgname == gamename .. ".nodeheartR" then
        return
    end

    Print('------ begin response --------')
    Print(msghead)
    Print(msgbody)
	Print('------ end response ----------')
end

--处理回应包
local function handle_response(cur_fd, msghead, msgbody)
    if msghead and msgbody then
		local name = msghead.msgname
        if name == "authR" then
            local msg = {
                gate_ip = "127.0.0.1",
                rid = msgbody.rid,
                gateport = msgbody.gateport,    
                expiretime = msgbody.expiretime,
                gatetoken = msgbody.gatetoken,
                username = msgbody.username,
                cpass = msgbody.cpass,
            }
            local fd = socket.connect(msg.gate_ip, msg.gateport)
            if fd then
                login_fds[cur_fd] = msg.rid
                gate_fds[msg.rid] = fd
                game_fds[msg.rid] = fd
                gatefd_to_rid[fd] = msg.rid
                NetTool.send_request(fd, "entergame", {rid=msg.rid, uid=msg.uid, gatetoken=msg.gatetoken,expiretime = msg.expiretime,agencyrid = msg.agencyrid, clientver = "0000"})
            end
        elseif name == "entergameR" then
            NetTool.send_request(cur_fd, gamename .. ".entertable", {level_type = 1})
        elseif name == gamename ..".entertableR" then
            NetTool.send_request(cur_fd, gamename .. ".sitdowntable", {})
        elseif name == gamename .. ".sitdowntableR" then
            NetTool.send_request(cur_fd, gamename .. ".gameready", {})
        elseif name == gamename .. ".gamereadyR" then
            ready_fds[cur_fd] = true
            --老虎机设置自动开始   
            auto_start(cur_fd)
        elseif name == (gamename .. ".todoN") then
            --水果机设置下注
            local tm = tonumber(msgbody.action_timeout_time) - os.time()
            --上庄
            --NetTool.send_request(cur_fd, gamename .. ".doaction", {action_type = 4, cur_upbanker_money = 50000})
            random_bet(cur_fd, tm)
        end

        if string.sub(name,-1) == "R" then
            return 1
        end
        return true
	end
	
    return false
end

--------------------------

--发送请求
function NetTool.send_request(fd, msgname, msg)
    if msgname ~= "heart" then
        print_request(msgname,msg)
    end
	
	local str = decode.c2spack(protobuf, msgname, msg)
	send_package(fd, str)
end

--处理响应
function NetTool.dispatch_package(fd)
	while true do
		local v = recv_package(fd)
		if not v  or v == "" then
			break
        elseif v == -1 then
            return -1
		else
            local msghead,msgbody = decode.s2cunpack(protobuf, v)
            print_response(msghead,msgbody)
            return handle_response(fd,msghead,msgbody)
        end
	end
end

--登录
function NetTool.login(ip,port)
    ip = ip or "192.168.6.213"
    port = port or 8191

    if not NetTool.is_init then
        error "must be init tool"
    end

    local status = nil
    local fd = socket.connect(ip, port)
    if fd then
        local username = "46634e1c0013cdea0172" .. math.random(100000,999999)
		local newtoken = gentoken(username)
		NetTool.send_request(fd, "authguest", {username = username, logintoken = newtoken})
        login_fds[fd] = nil
        
    else
        print("---error---")
        return
    end

    --login
    while true do
        status = NetTool.dispatch_package(fd)
        if status == false or status == -1 then
            return socket.close(fd)
        elseif login_fds[fd] then
            break
        else
            coroutine.yield(true)
        end
    end
    socket.close(fd)

    --gate
    local rid = login_fds[fd]
    fd = gate_fds[rid]
    while true do
        status = NetTool.dispatch_package(fd)
        if status == false or status == -1 then
            return socket.close(fd)
        elseif game_fds[rid] then
            break
        else
            coroutine.yield(true)
        end
    end

    --game
    local cnt = 1
    local heartmsg = "heart"
    local last_heartime = os.time()
    fd = game_fds[rid]
    while true do
        local isok = NetTool.dispatch_package(fd)
        if isok == -1 then
            break
        elseif not ready_fds[fd] then
            socket.usleep(100)
            cnt = cnt + 1
            if cnt > 2000 then
                break
            end
        else
            local now = os.time()
            if (now - last_heartime) > 3 then
                last_heartime = now
                NetTool.send_request(fd, heartmsg, {})
            end
            coroutine.yield(isok)
        end
    end
    socket.close(fd)
end

--初始化
function NetTool.init(nodename,isprint)
    NetTool.is_init = true
    gamename = nodename or "sgj"
    if not isprint or isprint == "false" 
    or tonumber(isprint) == 0 then
        is_print = false
    else
        is_print = true
    end
end

return NetTool
